package com.oystertech.sportcms.controller;

import cn.hutool.core.util.StrUtil;
import com.oystertech.sportcms.common.constant.SecurityConstants;
import com.oystertech.sportcms.common.result.Result;
import com.oystertech.sportcms.common.util.RequestUtils;
import com.oystertech.sportcms.model.dto.CaptchaResult;
import com.oystertech.sportcms.model.dto.LoginResult;
import com.oystertech.sportcms.security.JwtTokenManager;
import com.oystertech.sportcms.security.captcha.EasyCaptchaService;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Tag(name = "01.认证中心")
@RestController
@RequestMapping("/api/v1/auth")
@RequiredArgsConstructor
@Slf4j
public class AuthController {
	private final AuthenticationManager authenticationManager;
	private final JwtTokenManager jwtTokenManager;
	private final EasyCaptchaService easyCaptchaService;
	private final RedisTemplate redisTemplate;

	@Operation(summary = "登录")
	@PostMapping("/login")
	public Result<LoginResult> login(
			@Parameter(description = "用户名") @RequestParam String username,
			@Parameter(description = "密码") @RequestParam String password
	) {
		UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
				username.toLowerCase().trim(),
				password
		);
		Authentication authentication = authenticationManager.authenticate(authenticationToken);

		// 生成token
		String accessToken = jwtTokenManager.createToken(authentication);
		LoginResult loginResult = LoginResult.builder()
				.tokenType("Bearer")
				.accessToken(accessToken)
				.build();
		return Result.success(loginResult);
	}

	@Operation(summary = "注销", security = {@SecurityRequirement(name = SecurityConstants.TOKEN_KEY)})
	@DeleteMapping("/logout")
	public Result logout(HttpServletRequest request) {
		String token = RequestUtils.resolveToken(request);
		if (StrUtil.isNotBlank(token)) {
			Claims claims = jwtTokenManager.getTokenClaims(token);
			String jti = claims.getId();

			Date expiration = claims.getExpiration();
			if (expiration != null) {
				// 有过期时间，在token有效时间内存入黑名单，超出时间移除黑名单节省内存占用
				long ttl = (expiration.getTime() - System.currentTimeMillis());
				redisTemplate.opsForValue().set(SecurityConstants.BLACK_TOKEN_CACHE_PREFIX + jti, null, ttl, TimeUnit.MILLISECONDS);
			} else {
				// 无过期时间，永久加入黑名单
				redisTemplate.opsForValue().set(SecurityConstants.BLACK_TOKEN_CACHE_PREFIX + jti, null);
			}
		}
		SecurityContextHolder.clearContext();
		return Result.success("注销成功");
	}

	@Operation(summary = "获取验证码")
	@GetMapping("/captcha")
	public Result getCaptcha() {
		CaptchaResult captcha = easyCaptchaService.getCaptcha();
		return Result.success(captcha);
	}

}
